import java.util.Random;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

/**
 * Semaphore (信号量) 示例代码
 * 模拟场景：5 辆汽车抢占 3 个停车位。
 *
 * @author GAX
 * @date 2025-09-08
 */
public class SemaphoreDemo {
    public static void main(String[] args) {
        // 1. 创建一个 Semaphore 实例，初始化许可证数量为 3。
        // 这就好比一个停车场，里面总共有 3 个车位。
        Semaphore semaphore = new Semaphore(3);

        // 2. 模拟 5 辆汽车（5个线程）来抢占车位。
        // 线程数大于许可证数，才能体现出 Semaphore 的流量控制作用。
        for (int i = 1; i <= 5; i++) {
            // 创建并启动线程，并为每个线程（汽车）命名，方便观察。
            new Thread(() -> {
                try {
                    // 3. 尝试获取一个许可证（抢占车位）。
                    // 如果许可证数量 > 0，则成功获取，计数器减 1，线程继续执行。
                    // 如果许可证数量 = 0，则线程进入等待队列，直到有其他线程释放许可证。
                    semaphore.acquire();

                    // 线程成功获取许可证后的业务逻辑
                    System.out.println(Thread.currentThread().getName() + "\t" + ">>>>>> 成功抢到车位");

                    // 4. 模拟停车时间，随机停留 1 到 3 秒。
                    TimeUnit.SECONDS.sleep(new Random().nextInt(3) + 1);

                    System.out.println(Thread.currentThread().getName() + "\t" + "<<<<<< 停车结束，准备离开");

                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                } finally {
                    // 5. 释放许可证（腾出车位）。
                    // 这个操作必须放在 finally 块中，以确保无论 try 块中是否发生异常，
                    // 许可证最终都能被释放，防止“死锁”或资源泄漏。
                    semaphore.release();
                }
            }, "汽车-" + i).start(); // 为线程命名，如 "汽车-1", "汽车-2" ...
        }
    }
}